//carousel

//采用面向对象的方式来进行编程

//类

//会大量操作到dom

//1.构建一个工具类,专门用于操作dom

class Tools {
    //1.获取dom
    //jsdoc
    /**
     * 
     * @param {String} selector 一个选择器
     * @returns {Node} 返回一个dom节点
     */
    $ = selector => document.querySelector(selector);
    //2.创建dom元素的方法
    /**
     * 
     * @param {String} tagName 标签名
     * @returns {elemnt} 返回一个创建好的dom元素
     */
    _c = tagName => document.createElement(tagName)
    //3.操作元素的样式
    /**
     * 
     * @param {Element} el 要设置样式的元素
     * @param  {Object|String} arg 设置的样式,可以是对象,也可以是字符串
     */
    css = (el, ...arg) => {
        // console.log(arg)
        //处理arg是对象还是字符串
        //不同的参数对应不同的处理方式
        //后面的jquery就是这么玩 玩封装
        if (arg && typeof arg[0] === "object") {
            for (let k in arg[0]) {
                el.style[k] = arg[0][k]
            }
        } else if (arg && typeof arg[0] === 'string') {
            el.style[arg[0]] = arg[1]
        }

    }
}


//2.开始构建轮播图的类

//2.1 鼠标移动到轮播图上面的时候 左右两个箭头要显示出来

//2.2 点击两个箭头让图片进行滑动

class Carousel extends Tools {
    constructor() {
        //使用了extends 使用this的时候 一定要调用super
        super()
        //获取一些元素,添加到当前的实例
        //获取容器
        this.container = this.$('.container')
        //获取箭头
        this.arrow = this.$('.arrow')
        this.leftArrow = this.$('.arrow .left')
        this.rightArrow = this.$('.arrow .right')
        // console.log(this.arrow)
        //获取要移动的ul元素 wrap
        this.uu = this.$('.wrap');
        //定义初始图片的移动索引
        this.picIndex = 0;
        //获取一张图片的宽度 mask遮罩的宽度就是一张图片的宽度
        this.onePicWidth = this.$('.mask').offsetWidth;
        //获取轮播图的所有的li
        this.lis = this.uu.children;
        //获取指示器的容器
        this.indicator = this.$('.indicator')
        //定义一个用于判断无缝轮播的属性
        this.isCircular = false;
        //动态设定ul容器的宽度
        this.css(this.uu, "width", this.lis.length * this.onePicWidth + "px")
        //用于标记是否开启自动轮播
        this.isAutoplay = false;
        //将自动轮播的间隔时间,存到实例中
        this.delay = 1000;
    }
    //绑定鼠标事件
    bindMouseEvent = () => {
        //鼠标移动到容器 让箭头显示
        this.container.addEventListener('mouseenter', () => {
            //停止自动轮播
            this.stop()
            this.css(this.arrow, "display", "block")
        })
        //鼠标移出容器 让箭头隐藏

        this.container.addEventListener('mouseleave', () => {
            //鼠标离开继续自动轮播
            this.play(this.delay)
            this.css(this.arrow, 'display', 'none')
        })

        //给箭头注册事件 事件委托的方式注册的
        this.arrow.addEventListener('click', (e) => {
            // console.log(e.target.className)
            switch (e.target.className) {
                case 'left':
                    this.prev()
                    return
                case 'right':
                    this.next()

            }
        })

        //通过事件委托的方式给指示器绑定事件

        this.indicator.addEventListener('click', (e) => {
            // console.log(e.target)
            if (e.target.localName === "li") {
                let _this = e.target;
                // console.log(_this.index)
                this.picIndex = _this.index; //2
                this.slide()

            }
        })
    }
    //让指示器高亮的方法
    bindIndicatorActive() {
        let indicators = this.indicator.children;
        // console.log(indicators)
        //如果显示了指示器,才进行下面的逻辑操作
        if (indicators.length) {
            //将这个元素集合变成一个数组,那么可以调用数组的方法
            indicators = [...indicators];
            // console.log(indicators)
            //清掉所有的类名
            indicators.forEach(li => {
                li.className = ""
            })

            //要判断是否开启了无缝轮播,如果开启了,当picIndex走到 this.lis.length -1 (5)的时候,直接让第1个指示器按钮(索引:0)高亮
            // console.log(this.picIndex)
            if (this.isCircular && this.picIndex === this.lis.length - 1) {
                // console.log('判断进入了')
                indicators[0].className = "active"
            } else {
                indicators[this.picIndex].className = "active"
            }

        }
    }
    //让图片滑动的方法
    slide() {
        //调用动画方法
        animate(this.uu, -this.onePicWidth * this.picIndex)
        this.bindIndicatorActive() //调用让指示器按钮高亮的方法
    }

    //切换到上一张
    prev() {
        //如果开启了无缝轮播
        if (this.isCircular && this.picIndex === 0) {
            // console.log(-(this.lis.length - 1) * this.onePicWidth)
            //瞬间将uu的left位置放到最后一张
            this.css(this.uu, 'left', -(this.lis.length - 1) * this.onePicWidth + "px");
            //将picIndex变成最后一张
            this.picIndex = this.lis.length - 1
        }
        this.picIndex--
        //如果没有开启无缝轮播
        if (!this.isCircular) {
            if (this.picIndex < 0) {
                this.picIndex = this.lis.length - 1
            }
        }
        // console.log(this.picIndex)
        this.slide()
    }
    //下一张
    next() {
        // console.log(this.picIndex)

        //如果开启了无缝轮播

        if (this.isCircular && this.picIndex === this.lis.length - 1) {
            //立马是手动的将轮播图的位置left设置为0,并且picIndex也要变成0
            this.css(this.uu, 'left', 0);
            this.picIndex = 0;
        }

        this.picIndex++ //3

        if (!this.isCircular) {//没有开启无缝轮播的边界处理
            if (this.picIndex === this.lis.length) {
                // console.log('这次操作要处理')
                this.picIndex = 0;
            }
        }
        this.slide()
    }
    //创建指示器按钮
    createIndicatorBtn() {
        //声明一个变量,用于控制循环次数
        let len;
        //如果开启了无缝轮播,那么循环就要少一次
        if (this.isCircular) {
            len = this.lis.length - 1
        } else {
            //如果没有就不要少一次 正常使用this.lis.length
            len = this.lis.length
        }


        //根据轮播图的长度,动态的创建指示器的数量
        for (let i = 0; i < len; i++) {
            //动态创建指示器,动态创建元素
            let li = this._c('li');
            // 设置指示器按钮的内容
            li.innerText = i + 1;
            //给每个li元素都添加一个index
            li.index = i;
            //将创建好的指示器按钮添加到指示器容器中
            this.indicator.appendChild(li)
        }
    }

    //隐藏指示器

    hideIndicator() {
        //移除创建出来的指示器按钮
        this.indicator.innerHTML = "";
        this.css(this.indicator, 'display', 'none')
    }

    //显示指示器
    showIndicator() {
        //调用创建指示器的方法
        this.createIndicatorBtn()
        //设置指示器显示
        this.css(this.indicator, "display", 'block')
        this.bindIndicatorActive() //调用让指示器按钮高亮的方法
    }
    //在类里面 方法的编写是不用按顺序的
    //控制轮播图开启无缝轮播
    circular() {
        //让标记是否开启无缝轮播的属性 变成true
        this.isCircular = true;
        //将目前轮播图中的第一张图片克隆到最后
        let cloneFirst = this.lis[0].cloneNode(true)
        // console.log(cloneFirst)
        //将这个元素添加到uu容器的最后
        this.uu.appendChild(cloneFirst)
        //因为多添加了一个元素,所以需要重新设定整个uu容器的宽度
        this.css(this.uu, 'width', this.lis.length * this.onePicWidth + "px")
    }
    //play 轮播图片
    play(delay) {
        //为了防止重复的设定定时器,导致图片播放越来越快,设定之前都要清除上一个定时器
        // console.log(this.interval)
        if (this.interval) {
            //如果上面还有定时器,那么调用stop清除之前的定时器
            this.stop()
        }
        //将定时器添加到方便后面的清除
        this.interval = setInterval(() => {
            this.next()
        }, delay)
    }
    //stop 停止轮播
    stop() {
        clearInterval(this.interval)
    }
    //自动轮播
    autoplay(delay = 1000) {
        //将自动轮播这个属性标记为true
        this.isAutoplay = true;
        //设定实例上delay的值
        this.delay = delay;
        // console.log(window.onblur)
        //为了防止多次调用auto 设定多个不同的处理函数 导致onfocus和onblur不触发的问题
        if (!window.onblur && !window.onfocus) {
            //窗口失去焦点 window.onblur 
            window.onblur = () => {
                console.log('窗口失去了焦点')
                //停止轮播就行了
                this.stop()
            }
            //窗口获取焦点 window.onfocus
            window.onfocus = () => {
                console.log('浏览器获得了焦点')
                console.log('delay===' + this.delay)
                this.play(this.delay)
            }
        }

        //调用播放的方法 首次进来的时候 自动轮播

        this.play(this.delay)

    }
}

let c = new Carousel

// console.log(c)

//耦合度高 面向对象就应该低耦合

//代码和代码的关联程度高 就叫做高耦合

//我们要解耦

//我们实现的目标 就是 我们这个轮播图对象的方法 调用不应该分先后顺序

//circular和showIndicator调用顺序不同 导致的结果不同


c.bindMouseEvent()

c.showIndicator()

c.circular()

//添加需求:
//1.自己可以定义轮播的间隔时间
//2.页面切换的时候,回到轮播图页面,会一次播放很多张,这个问题需要处理
//3.鼠标移入的时候 停止自动轮播 鼠标离开 继续自动轮播(如果开启了自动轮播的情况下)
c.autoplay(1000)



